#pragma once

#include <iostream>
#include <functional>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"
#include "Thread.hpp"

namespace ns_client
{
    const static uint16_t default_port = 8080; // 默认端口号

    class UdpClient
    {
    public:
        UdpClient(const std::string& ip, uint16_t port = default_port)
            : ip_(ip), port_(port)
        {
            std::cerr << ip << " : " << port << std::endl;

            precv_ = new Thread(0, std::bind(&UdpClient::Recv, this));
            psend_ = new Thread(1, std::bind(&UdpClient::Send, this));
        }


        ~UdpClient()
        {
            psend_->join();
            precv_->join();

            delete (psend_);
            delete (precv_);
        }

        void StartClient()
        {
            // 创建套接字
            sock_ = socket(AF_INET, SOCK_DGRAM, 0);
            if (sock_ == -1)
            {
                std::cerr << "Create Socket Fail: " << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }
            std::cerr << "Create Socket Succese: " << sock_ << std::endl;

            svr_.sin_family = AF_INET;
            svr_.sin_port = htons(port_);
            svr_.sin_addr.s_addr = inet_addr(ip_.c_str());

            // 需要绑定，但不由我们手动绑定
            // OS TODO

            //启动线程
            precv_->run();
            psend_->run();
        }

        void Recv()
        {
            while (true)
            {
                // 发信息
                std::string msg;
                std::cerr << "Please Enter >>";
                std::getline(std::cin, msg);

                socklen_t len = sizeof svr_;
                sendto(sock_, msg.c_str(), msg.size(), 0, (struct sockaddr*)&svr_, len);
            }
        }

        void Send()
        {
            char buffer[1024] = { 0 };

            while (true)
            {
                // 收信息
                socklen_t len = sizeof svr_;
                int n = recvfrom(sock_, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&svr_, &len);
                if (n > 0) buffer[n] = '\0';
                else continue;

                // 获取服务端的信息
                std::cout << buffer << std::endl;
            }
        }

    private:
        int sock_;        // 套接字
        std::string ip_;  // IP地址
        uint16_t port_;   // 端口
        sockaddr_in svr_; // 服务端信息

        Thread* precv_;
        Thread* psend_;
    };
}